package catan.board;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import catan.tiles.Tile;
import catan.tiles.TileType;

/**
 * A class for creation of a board.
 * @author jsilva
 */
public class Board {
	
	/**
	 * @return Default configuration of the board.
	 */
	private static final int[] DEFAULT_TILE_COUNTS() {
		int[] counts = new int[TileType.values().length];
		counts[TileType.BRICK.ordinal()] = 3;
		counts[TileType.ORE.ordinal()] = 3;
		counts[TileType.WHEAT.ordinal()] = 4;
		counts[TileType.WOOD.ordinal()] = 4;
		counts[TileType.WOOL.ordinal()] = 4;
		counts[TileType.DESERT.ordinal()] = 1;		
		return counts;
	}
	
	/**
	 * Defines what numbers will show up on tiles
	 * Will be copied as many times as required to give all tiles a number;
	 * for the last copy, only some numbers might be used (from the beginning).
	 */
	private static final int[] ROLL_NUM_DISTRO = 
		{6, 8, 5, 9, 4, 10, 3, 11, 2, 12};
	
	/**
	 * Creates a board with the default configuration.
	 */
	public Board() {
		this(DEFAULT_TILE_COUNTS());
	}
	
	/**
	 * Creates a board with the given configuration.
	 * @param tile_counts Array defining the count of each resource
	 *     type, where each index corresponds to a TileType ordinal.
	 */
	public Board(int[] tile_counts) {		
				
		int total_tiles = 0;
		for (int i = 0; i < tile_counts.length; i++) {
			total_tiles += tile_counts[i];
		}
		
		// Create and shuffle a list of tiles to place
		List<TileType> types_left = new LinkedList<TileType>();
		for (TileType t : TileType.values()) {
			for (int i = 0; i < tile_counts[t.ordinal()]; i++) {
				types_left.add(t);
			}
		}
		Collections.shuffle(types_left);
		
		// Create and shuffle a list of roll_nums to put on tiles.
		List<Integer> roll_nums = new LinkedList<Integer>();
		int non_desert = total_tiles - tile_counts[TileType.DESERT.ordinal()];
		for (int i = 0; i < non_desert; i++) {
			roll_nums.add(ROLL_NUM_DISTRO[i % ROLL_NUM_DISTRO.length]);
		}
		Collections.shuffle(roll_nums);
		
		// Keeps track of where we are in the board
		// that we're generating. We will add tiles around
		// this tile until it is surrounded.
		Tile cur_tile = null;
		Tile neighbour_tile = null;
		TileType cur_type = null;
		int cur_pos = 0;
		int cur_depth = 0;
		int roll_number = 0;		
		
		// Create the centremost tile
		cur_type = types_left.get(total_tiles - 1);
		roll_number = roll_nums.get(total_tiles - 1);
		cur_tile = new Tile(cur_type, roll_number, cur_depth, cur_pos);
		
		total_tiles--;
		
		while (total_tiles > 0) {
			
			// Create all of the neighbouring tiles
			while (cur_pos < Tile.HEX_SIDES) {
				cur_type = types_left.get(total_tiles - 1);
				roll_number = roll_nums.get(total_tiles - 1);
				
				if (cur_tile.getNeighbours().get(cur_pos) == null) {
					neighbour_tile = new Tile(cur_type, roll_number, cur_depth, cur_pos);
					cur_tile.setNeighbour(cur_pos, neighbour_tile);
					
					if (cur_pos != 0) {
						if (cur_pos == 1) {
							neighbour_tile.setNeighbour(Tile.HEX_SIDES - 1, cur_tile.getNeighbours().get(cur_pos - 1));
						} else if (cur_pos == Tile.HEX_SIDES - 1) {
							neighbour_tile.setNeighbour(Tile.HEX_SIDES - 3, cur_tile.getNeighbours().get(cur_pos - 1));
							neighbour_tile.setNeighbour(1, cur_tile.getNeighbours().get(cur_pos - 1));
						} else {
							neighbour_tile.setNeighbour(cur_pos - 2, cur_tile.getNeighbours().get(cur_pos - 1));
						}
					}
				}
				
				cur_pos++;
				total_tiles--;
			}
			
			cur_depth++;
			cur_pos = 0;
			
			if (cur_tile.getNeighbours().get(0) != null) {
				cur_tile = cur_tile.getNeighbours().get(0);
			} else if (cur_tile.getNeighbours().get(1) != null) {
				cur_tile = cur_tile.getNeighbours().get(1);
			}
		}
	}
	
}
